home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C101.ZIP / UUPC11XS.ZIP / UUCICO / ULIB.C < prev    next >
C/C++ Source or Header  |  1992-12-12  |  21KB  |  583 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    u l i b . c                                                     */
  3. /*                                                                    */
  4. /*    Serial port interface to COMMFIFO.ASM for MS-DOS                */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989 by Andrew H. Derbyshire.  Changes    */
  9. /*    Copyright (c) 1990-1992 by Kendra Electronic Wonderworks;       */
  10. /*    all rights reserved except those explicitly granted by the      */
  11. /*    UUPC/extended license.                                          */
  12. /*--------------------------------------------------------------------*/
  13.  
  14. /*
  15.  *    $Id: ULIB.C 1.5 1992/12/12 16:12:13 ahd Exp $
  16.  *
  17.  *    $Log: ULIB.C $
  18.  * Revision 1.5  1992/12/12  16:12:13  ahd
  19.  * Include header file for definition for memory avail routines
  20.  *
  21.  * Revision 1.4  1992/12/07  02:43:20  ahd
  22.  * Improve error message when low memory prevents COMM port install
  23.  *
  24.  * Revision 1.3  1992/11/29  22:09:10  ahd
  25.  * Use sopen() rather than FOPEN() to avoid retries on comm port
  26.  *
  27.  * Revision 1.2  1992/11/21  06:17:42  ahd
  28.  * Delete old (pre-COMMFIFO) autobaud function
  29.  *
  30.  */
  31.  
  32. /*--------------------------------------------------------------------*/
  33. /*                        System include files                        */
  34. /*--------------------------------------------------------------------*/
  35.  
  36. #include <fcntl.h>
  37. #include <io.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <time.h>
  42. #include <share.h>
  43.  
  44. #ifdef __TURBOC__
  45. #include <alloc.h>
  46. #endif
  47.  
  48. /*--------------------------------------------------------------------*/
  49. /*                    UUPC/extended include files                     */
  50. /*--------------------------------------------------------------------*/
  51.  
  52. #include "lib.h"
  53. #include "hlib.h"
  54. #include "ulib.h"
  55. #include "comm.h"
  56. #include "ssleep.h"
  57. #include "catcher.h"
  58.  
  59. /*--------------------------------------------------------------------*/
  60. /*                        Internal prototypes                         */
  61. /*--------------------------------------------------------------------*/
  62.  
  63. static void ShowModem( void );
  64.  
  65. /*--------------------------------------------------------------------*/
  66. /*                          Global variables                          */
  67. /*--------------------------------------------------------------------*/
  68.  
  69. boolean   port_active = FALSE;  /* TRUE = port handler handler active  */
  70.  
  71. static BPS current_bps;
  72. static char current_direct;
  73. static boolean carrierdetect;
  74.  
  75. currentfile();
  76.  
  77. /* IBM-PC I/O routines */
  78.  
  79. /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
  80.  
  81. /*************** BASIC I/O ***************************/
  82. /* Saltzers serial package (aka Info-IBMPC COM_PKG2):
  83.  * Some notes:  When packets are flying in both directions, there seems to
  84.  * be some interrupt handling problems as far as receiving.  Checksum errors
  85.  * may therefore occur often even though we recover from them.  This is
  86.  * especially true with sliding windows.  Errors are very few in the VMS
  87.  * version.  RH Lamb
  88.  */
  89.  
  90.  
  91. #define  STOPBIT  1
  92. #define LINELOG "LineData.Log"      /* log serial line data here */
  93.  
  94. static int log_handle;
  95. static int logmode = 0;             /* Not yet logging            */
  96. #define WRITING 1
  97. #define READING 2
  98. static FILE *log_stream;
  99. static int com_handle;
  100. static boolean hangup_needed = TRUE;
  101.  
  102. /*--------------------------------------------------------------------*/
  103. /*    o p e n l i n e                                                 */
  104. /*                                                                    */
  105. /*    Open the serial port for I/O                                    */
  106. /*--------------------------------------------------------------------*/
  107.  
  108. int openline(char *name, BPS bps, const boolean direct)
  109. {
  110.    int   value;
  111.  
  112.    if (port_active)              /* Was the port already active?     ahd   */
  113.       closeline();               /* Yes --> Shutdown it before open  ahd   */
  114.  
  115.    printmsg(15, "openline: %s, %d", name, bps);
  116.  
  117.    logmode = 0;
  118.  
  119.    current_direct = (char) (direct ? 'D' : 'M') ;
  120.  
  121.    if (sscanf(name, "COM%d", &value) != 1)
  122.    {
  123.       printmsg(0,"Communications port must be format COMx, was %s",
  124.                 name);
  125.       panic();
  126.    }
  127.  
  128.    norecovery = FALSE;
  129.  
  130.    com_handle = sopen( name, O_BINARY | O_RDWR, SH_DENYRW );
  131.                                  /* Used soly for lock abilities  */
  132.    if ( com_handle == -1 )
  133.    {
  134.       printerr( name );
  135.       return 1;
  136.    }
  137.  
  138.    select_port(value);
  139.    save_com();
  140.  
  141.    if (!install_com())
  142.    {
  143.       printmsg(0,"Commuications handler install failed; "
  144.                   "probable cause ... memory shortage.");
  145.  
  146. #ifdef __TURBOC__
  147.       printmsg(0,"FAR DOS Memory free = %ld bytes",
  148.                   farcoreleft() );
  149. #endif
  150.  
  151.       return 1;
  152.    }
  153.  
  154.    open_com(bps, current_direct, 'N', STOPBIT, 'D');
  155.    current_bps = bps;
  156.    dtr_on();
  157.    ssleep(2);                 /* Wait two seconds as required by V.24   */
  158.    carrierdetect = FALSE;     /* No modem connected yet                 */
  159.  
  160. /*--------------------------------------------------------------------*/
  161. /*        Log serial line data only if log file already exists        */
  162. /*--------------------------------------------------------------------*/
  163.  
  164.    log_handle = open(LINELOG, O_WRONLY | O_TRUNC | O_BINARY);
  165.    if (log_handle != -1) {
  166.       printmsg(15, "openline: logging serial line data to %s", LINELOG);
  167.       log_stream = fdopen(log_handle, "wb");
  168.    }
  169.  
  170.    port_active = TRUE;     /* record status for error handler */
  171.  
  172.    return 0;
  173.  
  174. } /*openline*/
  175.  
  176.  
  177. /*--------------------------------------------------------------------*/
  178. /*    s r e a d                                                       */
  179. /*                                                                    */
  180. /*    Read from the serial port                                       */
  181. /*                                                                    */
  182. /*    Non-blocking read essential to "g" protocol.  See               */
  183. /*    "dcpgpkt.c" for description.  This all changes in a             */
  184. /*    multi-tasking system.  Requests for I/O should get queued       */
  185. /*    and an event flag given.  Then the requesting process (e.g.     */
  186. /*    gmachine()) waits for the event flag to fire processing         */
  187. /*    either a read or a write.  Could be implemented on VAX/VMS      */
  188. /*    or DG but not MS-DOS.                                           */
  189. /*--------------------------------------------------------------------*/
  190.  
  191. unsigned int sread(char *buffer, unsigned int wanted, unsigned int timeout)
  192. {
  193.    time_t start;
  194.  
  195.    hangup_needed = TRUE;
  196.  
  197.    start = time(nil(time_t)); /* Remember when we started processing */
  198.  
  199. /*--------------------------------------------------------------------*/
  200. /*                  Report the current modem status                   */
  201. /*--------------------------------------------------------------------*/
  202.  
  203.    ShowModem();
  204.  
  205. /*--------------------------------------------------------------------*/
  206. /*             Now actually try to read a buffer of data              */
  207. /*--------------------------------------------------------------------*/
  208.  
  209.    for ( ; ; )
  210.    {
  211.       unsigned int pending;
  212.       pending = r_count_pending();
  213.  
  214.       if ( terminate_processing )
  215.       {
  216.          static boolean recurse = FALSE;
  217.          if ( ! recurse )
  218.          {
  219.             printmsg(2,"sread: User aborted processing");
  220.             recurse = TRUE;
  221.          }
  222.          return 0;
  223.       }
  224.  
  225.       printmsg(20, "sread: pending=%d, wanted=%d", pending, wanted);
  226.  
  227.       if (pending >= wanted) {   /* got enough in the buffer? */
  228.          unsigned int i;
  229.          for (i = 0; i < wanted; i++)
  230.             *buffer++ = (char) receive_com();
  231.  
  232.          if (log_handle != -1)
  233.          {
  234. #ifdef VERBOSE
  235.             char s[18];
  236. #endif
  237.             buffer -= wanted;
  238.             if (logmode != READING)
  239.             {
  240.                fputs("\nRead:  ", log_stream);
  241.                logmode = READING;
  242.             } /* if */
  243. #ifdef VERBOSE
  244.             for (i = 0; i < wanted; i++) {
  245.                itoa(0x100 | (unsigned) *buffer++, s, 16);
  246.                                              /* Make it printable hex */
  247.                fwrite(s, 1, 2, log_stream);  /* Write hex to the log    */
  248.             } /* for */
  249. #else
  250.             fwrite(buffer, 1, wanted, log_stream);
  251.                                              /* Write data to the log */
  252. #endif
  253.          } /* if (log_handle != -1) */
  254.  
  255.          return pending;
  256.       } else {
  257.          time_t   now     = time(nil(time_t));
  258.          time_t   elapsed = now - start;
  259.  
  260.          if (elapsed >= (long) timeout)
  261.             return pending;
  262.  
  263.          ddelay(0);                    /* Surrender our time slice   */
  264.  
  265.       } /* else */
  266.    } /* for ( ; ; ) */
  267.  
  268. } /*sread*/
  269.  
  270. /*--------------------------------------------------------------------*/
  271. /*    s w r i t e                                                     */
  272. /*                                                                    */
  273. /*    Write to the serial port                                        */
  274. /*--------------------------------------------------------------------*/
  275.  
  276. int swrite(char *data, unsigned int len)
  277. {
  278.    unsigned int i;
  279.  
  280.    hangup_needed = TRUE;
  281.  
  282. /*--------------------------------------------------------------------*/
  283. /*                      Report our modem status                       */
  284. /*--------------------------------------------------------------------*/
  285.  
  286.   ShowModem();
  287.  
  288. /*--------------------------------------------------------------------*/
  289. /*    Introduce a little flow control - Actual line pacing is         */
  290. /*    handled at a lower level                                        */
  291. /*--------------------------------------------------------------------*/
  292.  
  293.    if ( s_count_free() < (int) len )
  294.    {
  295.       int spin = 0;
  296.       static int const max_spin = 20;
  297.  
  298.       int queue_size = s_count_size();
  299.       int queue_free = s_count_free();
  300.  
  301.       if ( len > queue_size )
  302.       {
  303.          printmsg(0,"swrite: Transmit buffer overflow; buffer size %d, "
  304.                     "needed %d",
  305.                queue_size,len);
  306.          panic();
  307.       }
  308.  
  309.       while( (len > queue_free) && (spin < max_spin) )
  310.       {
  311.          int wait;
  312.          int needed;
  313.          int new_free;
  314.  
  315.          needed = max(queue_size/2, len-queue_free);
  316.                               /* Minimize thrashing by requiring
  317.                                  big chunks */
  318.  
  319.          wait = (int) ((long) needed * 10000L / (long) current_bps);
  320.                               /* Compute time in milliseconds
  321.                                  assuming 10 bits per byte           */
  322.  
  323.          printmsg(4,"swrite: Waiting %d milliseconds for %d bytes in queue"
  324.                      ", pass %d",
  325.                      wait, needed, spin);
  326.  
  327.          ddelay( wait );      /* Actually perform the wait           */
  328.  
  329.          new_free = s_count_free();
  330.  
  331.          if ( new_free == queue_free )
  332.             spin++;           /* No progress, consider timing out    */
  333.          else
  334.             queue_free = new_free;
  335.                               /* Update our progress                 */
  336.  
  337.       } /* while( (len > queue_free) && spin ) */
  338.  
  339.       if ( queue_free < len )
  340.       {
  341.          printmsg(0,"swrite: Transmit buffer overflow, needed %d bytes",
  342.                      len);
  343.       } /* if ( queue_free < len ) */
  344.       return 0;
  345.  
  346.    } /* if ( s_count_free() < len ) */
  347.  
  348. /*--------------------------------------------------------------------*/
  349. /*            Send the data to the communications package             */
  350. /*--------------------------------------------------------------------*/
  351.  
  352.    for (i = 0; i < len; i++)
  353.       send_com(*data++);
  354.  
  355. /*--------------------------------------------------------------------*/
  356. /*                Log the transmitted data, if desired                */
  357. /*--------------------------------------------------------------------*/
  358.  
  359.    if (log_handle != -1) {
  360. #ifdef VERBOSE
  361.       char s[18];
  362. #endif
  363.       if (logmode != WRITING)
  364.       {
  365.          fputs("\nWrite: ", log_stream);
  366.          logmode = WRITING;
  367.       } /* if */
  368.       data -= len;
  369. #ifdef VERBOSE
  370.       for (i = 0; i < len; i++) {
  371.          itoa(0x100 | (unsigned) *data++, s, 16);
  372.                                         /* Make it printable hex  ahd */
  373.          fwrite(s, 1, 2, log_stream);
  374.       } /* for */
  375. #else
  376.       fwrite(data, 1, len, log_stream);   /* Write data to the log */
  377. #endif
  378.    } /* if */
  379.  
  380. /*--------------------------------------------------------------------*/
  381. /*              Return byte count transmitted to caller               */
  382. /*--------------------------------------------------------------------*/
  383.  
  384.    return len;
  385.  
  386. } /*swrite*/
  387.  
  388.  
  389. /*--------------------------------------------------------------------*/
  390. /*    s s e n d b r k                                                 */
  391. /*                                                                    */
  392. /*    Send a break signal out the serial port                         */
  393. /*--------------------------------------------------------------------*/
  394.  
  395. void ssendbrk(unsigned int duration)
  396. {
  397.  
  398.    printmsg(12, "ssendbrk: %d", duration);
  399.  
  400.    break_com();
  401.  
  402. } /*ssendbrk*/
  403.  
  404.  
  405. /*--------------------------------------------------------------------*/
  406. /*    c l o s e l i n e                                               */
  407. /*                                                                    */
  408. /*    Close the serial port down                                      */
  409. /*--------------------------------------------------------------------*/
  410.  
  411. void closeline(void)
  412. {
  413.    int far *stats;
  414.  
  415.    if (!port_active)
  416.       panic();
  417.  
  418.    port_active = FALSE; /* flag port closed for error handler  */
  419.  
  420.    dtr_off();
  421.    ddelay(500);               /* Required for V.24             */
  422.    close_com();
  423.    restore_com();
  424.    close( com_handle );
  425.    norecovery = TRUE;
  426.  
  427.    if (log_handle != -1) {    /* close serial line log file */
  428.       fclose(log_stream);
  429.       close(log_handle);
  430.    };
  431.  
  432.    stats = com_errors();
  433.    printmsg(3, "Buffer overflows: %-4d",stats[COM_EOVFLOW]);
  434.    printmsg(3, "Receive overruns: %-4d", stats[COM_EOVRUN]);
  435.    printmsg(3, "Break characters: %-4d", stats[COM_EBREAK]);
  436.    printmsg(3, "Framing errors:   %-4d", stats[COM_EFRAME]);
  437.    printmsg(3, "Parity errors:    %-4d", stats[COM_EPARITY]);
  438.    printmsg(3, "Transmit errors:  %-4d", stats[COM_EXMIT]);
  439.    printmsg(3, "DSR errors:       %-4d", stats[COM_EDSR]);
  440.    printmsg(3, "CTS errors:       %-4d", stats[COM_ECTS]);
  441.  
  442. } /*closeline*/
  443.  
  444.  
  445. /*--------------------------------------------------------------------*/
  446. /*    H a n g u p                                                     */
  447. /*                                                                    */
  448. /*    Hangup the telephone by dropping DTR.  Works with HAYES and     */
  449. /*    many compatibles.                                               */
  450. /*    14 May 89 Drew Derbyshire                                       */
  451. /*--------------------------------------------------------------------*/
  452.  
  453. void hangup( void )
  454. {
  455.       if (!hangup_needed)
  456.          return;
  457.       hangup_needed = FALSE;
  458.       dtr_off();              /* Hang the phone up                         */
  459.       ddelay(500);            /* Really only need 250 milliseconds         */
  460.       dtr_on();               /* Bring the modem back on-line              */
  461.       ddelay(2000);           /* Now wait for the poor thing to recover    */
  462.                               /* two seconds is required by V.24           */
  463.       printmsg(3,"hangup: complete.");
  464.       carrierdetect = FALSE;  /* No modem connected yet                    */
  465.  
  466. } /* hangup */
  467.  
  468. /*--------------------------------------------------------------------*/
  469. /*    S I O S p e e d                                                 */
  470. /*                                                                    */
  471. /*    Re-specify the speed of an opened serial port                   */
  472. /*                                                                    */
  473. /*    Dropped the DTR off/on calls because this makes a Hayes drop    */
  474. /*    the line if configured properly, and we don't want the modem    */
  475. /*    to drop the phone on the floor if we are performing             */
  476. /*    autobaud.                                                       */
  477. /*                                                                    */
  478. /*    (Configured properly = standard method of making a Hayes        */
  479. /*    hang up the telephone, especially when you can't get it into    */
  480. /*    command state because it is at the wrong speed or whatever.)    */
  481. /*--------------------------------------------------------------------*/
  482.  
  483. void SIOSpeed(BPS bps)
  484. {
  485.  
  486.    printmsg(4,"SIOSspeed: Changing port speed from %ld BPS to %ld BPS",
  487.                (long) current_bps, (long) bps);
  488.    ioctl_com(0, bps);
  489.  
  490.    ShowModem();
  491.    current_bps = bps;
  492.  
  493. } /*SIOSpeed*/
  494.  
  495. /*--------------------------------------------------------------------*/
  496. /*    f l o w c o n t r o l                                           */
  497. /*                                                                    */
  498. /*    Enable/Disable in band (XON/XOFF) flow control                  */
  499. /*--------------------------------------------------------------------*/
  500.  
  501. void flowcontrol( boolean flow )
  502. {
  503.    printmsg(4,"flowcontrol: Closing port");
  504.    close_com();
  505.    ShowModem();
  506.    printmsg(4,"flowcontrol: Opening port to %sable flow control",
  507.                flow ? "en" : "dis");
  508.    open_com(current_bps, current_direct, 'N', STOPBIT, flow ? 'E' : 'D');
  509.    ShowModem();
  510.  
  511. } /*flowcontrol*/
  512.  
  513. /*--------------------------------------------------------------------*/
  514. /*    G e t S p e e d                                                 */
  515. /*                                                                    */
  516. /*    Report current speed of communications connection               */
  517. /*--------------------------------------------------------------------*/
  518.  
  519. BPS GetSpeed( void )
  520. {
  521.    return current_bps;
  522. } /* GetSpeed */
  523.  
  524. /*--------------------------------------------------------------------*/
  525. /*    C D                                                             */
  526. /*                                                                    */
  527. /*    Report if we have carrier detect and lost it                    */
  528. /*--------------------------------------------------------------------*/
  529.  
  530. boolean CD( void )
  531. {
  532.    boolean online = carrierdetect;
  533.  
  534.    ShowModem();
  535.    carrierdetect = is_cd_high();
  536.  
  537. /*--------------------------------------------------------------------*/
  538. /*    If we previously had carrier detect but have lost it, we        */
  539. /*    report it was lost.  If we do not yet have carrier detect,      */
  540. /*    we return success because we may not have connected yet.        */
  541. /*--------------------------------------------------------------------*/
  542.  
  543.    if (online)
  544.       return carrierdetect && is_dsr_high();
  545.    else
  546.       return is_dsr_high();
  547.  
  548. } /* CD */
  549.  
  550. /*--------------------------------------------------------------------*/
  551. /*    S h o w M o d e m                                               */
  552. /*                                                                    */
  553. /*    Report current modem status                                     */
  554. /*--------------------------------------------------------------------*/
  555.  
  556. #define mannounce(flag, bits, text ) ((flag & bits) ? text : "" )
  557.  
  558. static void ShowModem( void )
  559. {
  560.    static int old_status = 0xDEAD;
  561.    int status;
  562.  
  563.    if ( debuglevel < 4 )
  564.       return;
  565.  
  566.    status = modem_status();
  567.    if (status == old_status)
  568.       return;
  569.  
  570.    printmsg(0, "ShowModem: %#02x%s%s%s%s%s%s%s%s",
  571.       status,
  572.       mannounce(MDM_CD,   status, "\tCarrier Detect"),
  573.       mannounce(MDM_RI,   status, "\tRing Indicator"),
  574.       mannounce(MDM_DSR,  status, "\tData Set Ready"),
  575.       mannounce(MDM_CTS,  status, "\tClear to Send"),
  576.       mannounce(MDM_CDC,  status, "\tCD changed"),
  577.       mannounce(MDM_TRI,  status, "\tRI went OFF"),
  578.       mannounce(MDM_DSRC, status, "\tDSR changed"),
  579.       mannounce(MDM_CTSC, status, "\tCTS changed"));
  580.    old_status = status;
  581.  
  582. } /* ShowModem */
  583.